package com.wq.httpclientcore.config;

import com.wq.httpclientcore.entities.po.DbConnectionConfig;
import com.wq.httpclientcore.enums.DatabaseType;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.datasource.DataSourceException;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.StringJoiner;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Configuration
@EnableConfigurationProperties(HikariPoolConfig.class)
public class DynamicDataSourceConfig {
    private static final Map<Long, DataSource> dataSourceMap = new ConcurrentHashMap<>();
    private final HikariPoolConfig poolConfig;

    public DynamicDataSourceConfig(HikariPoolConfig poolConfig) {
        this.poolConfig = poolConfig;
    }

    /**
     * 获取或创建数据源（线程安全）
     */
    public DataSource getDataSource(DbConnectionConfig config) {
        return dataSourceMap.computeIfAbsent(config.getId(), k -> createDataSource(config));
    }

    /**
     * 创建并验证数据源
     */
    private DataSource createDataSource(DbConnectionConfig config) {
        validateConfig(config);
        try {
            DatabaseType dbType = DatabaseType.from(config.getDbType());
            HikariConfig hikariConfig = buildHikariConfig(config, dbType);
            HikariDataSource dataSource = new HikariDataSource(hikariConfig);
            testConnection(dataSource); // 立即测试连接有效性
            return dataSource;
        } catch (Exception e) {
            log.error("数据库连接创建失败 | 配置:{} | 错误:{}", config, e.getMessage());
            throw new DataSourceException("数据库连接失败: " + e.getMessage(), e);
        }
    }

    /**
     * 构建 Hikari 配置
     */
    private HikariConfig buildHikariConfig(DbConnectionConfig config, DatabaseType dbType) {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(buildJdbcUrl(config, dbType));
        hikariConfig.setUsername(config.getUsername());
        hikariConfig.setPassword(config.getPassword());
        hikariConfig.setDriverClassName(dbType.getDriverClass());

        // 应用连接池配置
        hikariConfig.setMaximumPoolSize(poolConfig.getMaximumPoolSize());
        hikariConfig.setMinimumIdle(poolConfig.getMinimumIdle());
        hikariConfig.setIdleTimeout(poolConfig.getIdleTimeout());
        hikariConfig.setConnectionTimeout(poolConfig.getConnectionTimeout());

        // 通用配置
        hikariConfig.setPoolName("HikariPool-" + config.getId());
        hikariConfig.setConnectionTestQuery("SELECT 1");
        return hikariConfig;
    }

    /**
     * 构建动态 JDBC URL
     */
    private String buildJdbcUrl(DbConnectionConfig config, DatabaseType dbType) {
        String baseUrl = String.format(
                dbType.getJdbcUrlTemplate(),
                config.getHost(),
                config.getPort(),
                config.getDbName()
        );

        switch (dbType) {
            case MYSQL:
                return baseUrl + "?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8";
            case POSTGRESQL:
                StringJoiner params = new StringJoiner("&");
                params.add("sslmode=disable");
                if (config.getSchemaName() != null) {
                    params.add("currentSchema=" + config.getSchemaName());
                }
                return baseUrl + "?" + params.toString();
            default:
                throw new IllegalStateException("不支持的数据库类型");
        }
    }

    /**
     * 配置基础校验
     */
    private void validateConfig(DbConnectionConfig config) {
        if (config.getHost() == null || config.getPort() == null || config.getDbName() == null) {
            throw new IllegalArgumentException("数据库连接配置不完整");
        }
    }

    /**
     * 连接有效性测试
     */
    private void testConnection(HikariDataSource dataSource) throws SQLException {
        try (Connection conn = dataSource.getConnection();
             Statement stmt = conn.createStatement()) {
            stmt.execute("SELECT 1");
        }
    }

    /**
     * 手动移除数据源（用于配置变更时）
     */
    public void evictDataSource(Long configId) {
        DataSource dataSource = dataSourceMap.remove(configId);
        if (dataSource instanceof HikariDataSource) {
            ((HikariDataSource) dataSource).close();
        }
    }
}